package org.moyu.interceptor;

import jakarta.annotation.Resource;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.moyu.config.properties.MoyuSystemPatternEnum;
import org.moyu.config.properties.MoyuSystemProperties;
import org.moyu.constant.SignalFilterConstant;
import org.moyu.exception.SignalException;
import org.moyu.utils.RedisUtils;
import org.moyu.utils.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
 *
 * @author 李伟国
 * 时间 2024年12月07日19:42:38
 * 描述 指纹拦截
 */


@Component
public class SignalFilter implements Filter, SignalFilterConstant {

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private MoyuSystemProperties modelProperties;

    /**
     * 拦截白名单
     * @param path 拦截路径
     * @return 是否需要拦截
     */
    private boolean shouldNotFilter(String path) {
        // 根据路径判断不应该被拦截的URL
        // 返回true则表示不拦截
        return path.startsWith("/y");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if(modelProperties.getPattern() != MoyuSystemPatternEnum.production){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 不管application/json之外的格式
        if(servletRequest.getContentType()!=null&&!"application/json".equals(
            servletRequest.getContentType())){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String url = request.getRequestURI();
        // 白名单内的不拦截
        if(shouldNotFilter(url)){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        String query = request.getQueryString();
        if(query==null){
            query = "";
        }
        url = url + "?" + query;
        url= URLDecoder.decode(url, StandardCharsets.UTF_8);
        // 获得时间戳
        String timestamp = request.getHeader(TIMESTAMP);
        // 获得随机字符串
        String random = request.getHeader(RANDOM);
        // 获得指纹
        String signal = request.getHeader(SIGNAL);
        if(ObjectUtils.isEmpty(timestamp)
                || ObjectUtils.isEmpty(random)
                || ObjectUtils.isEmpty(signal)){
            // 无关请求
            throw new SignalException("无关请求");
        }
        Object o = redisUtils.get(REDIS_SIGNAL_KEY + random);
        if(!ObjectUtils.isEmpty(o)){
            // 重复请求
            throw new SignalException("请求重复");
        }
        long localTimestamp = System.currentTimeMillis();
        long clientTimestamp = Long.parseLong(timestamp);
        if(localTimestamp-clientTimestamp>EXPORT_TIME){
            // 指纹超时
            throw new SignalException("请求超时");
        }

        CachedBodyRequest cachedBodyRequest = new CachedBodyRequest(request);
        String body = new String(cachedBodyRequest.getBody(), request.getCharacterEncoding());
        System.out.println("====================");
        System.out.println(body);
        System.out.println("====================");
        String originalData = timestamp+random+url+body;
        String originalMd5 = StringUtils.getMd5(originalData);
        if(!originalMd5.equals(signal)){
            // 指纹无效
            System.out.println(originalMd5);
            throw new SignalException("无效请求");
        }
        redisUtils.set(REDIS_SIGNAL_KEY+random, signal, EXPORT_TIME_SECONDS);
        filterChain.doFilter(cachedBodyRequest, servletResponse);
    }

}
